home *** CD-ROM | disk | FTP | other *** search
/ Aminet 22 / Aminet 22 (1997)(GTI - Schatztruhe)[!][Dec 1997].iso / Aminet / dev / e / amigae33a.lha / E_v3.3a / Src.lha / Src / Utils / Build / build.e < prev    next >
Text File  |  1997-10-26  |  13KB  |  438 lines

  1. /* build in E.
  2.  
  3. TODO:    - cyclic structure check (part)
  4.     - (amigados?) constants (part)
  5.  
  6. */
  7.  
  8. OPT OSVERSION=37
  9.  
  10. MODULE 'tools/file', 'dos/dosextens', 'dos/dos'
  11.  
  12. /*
  13.   symbol=object
  14.   object: dep1 dep2 ....
  15.      act1
  16.      act2
  17.  
  18.   $(symbol): $(symbol)bla ....
  19.      act1
  20.      ...
  21. */
  22.  
  23. /*
  24. history:
  25.  
  26. (Version 0.8 by Rob and Wouter)
  27.  
  28. When        Who        What
  29. 23.07.97    Glauschwuffel    - Added symbolic constants. Constants are allowed everywhere
  30. 26.07.97    Glauschwuffel    - Removed bug in constants: The part after the last constant
  31.                   wouldn't be copied. $(test): $(test).e crashed in cyclic
  32.                   dependancy. :(
  33.                 - Used source that Jason mailed me to get right order of actions.
  34.                 - Minor modification in traverse(): "circ" is raised when object
  35.                   and a dependancy have the same name. 
  36.                 - Added version facility :)
  37.                 - local constant $(target) is now available in actions
  38.                 - Added QUIET arg
  39. 27.07.97    Glauschwuffel    - Changed QUIET to VERBOSE since quiet was default for v3.1
  40. (between        Glauschwuffel   - Used EBuild with new oomodules/ objects. *Very* stable, no errrors
  41.                                           at all. I tend to say it's error-free <g>)
  42. 09.08.97    Glauschwuffel    - Actions of a target are now collected in a script again.
  43.                                           EBuild now acts as described in the Ev3.2 doc (except of the
  44.                                           modified $target). Bumped version to 0.9.
  45. 10.08.97    Glauschwuffel    - Added script variable $target for reasons of consistency. Now
  46.                                           $(target) and $target are possible.
  47.                                           Discovered a potential bug: if build is called without a target and
  48.                                           the first target in the buildfile is not a filename (e.g. a symbolic
  49.                                   target like `all' or `clean') the actions for this target are
  50.                                   executed anyway (0.8 does this, too).
  51. 05.09.97    Glauschwuffel    - BUG: the temporary script in T: won't be closed on exceptions
  52.                   Fixed.
  53. 13.09.97    Glauschwuffel    - ADD: commandline option CONSTANTS. Lists the constants before executing
  54.                   anything. Modified `dumpC()' for this.
  55. 12.10.97    Glauschwuffel    - BUG: EBuild would cause an enforcer hit when no dependent objects are
  56.                   specified (as with symbolic targets like 'clean'). target was only set
  57.                   when there were dependencies, moved the statement two lines higher.
  58.                   Fixed. Bumped version. Thanks to Nuno for the report.
  59. */
  60.  
  61. OBJECT object
  62.   next:PTR TO object
  63.   name:PTR TO CHAR
  64.   firstdep:PTR TO dependancy
  65.   firstaction:PTR TO action
  66.   child
  67.   lastaction:PTR TO action
  68. ENDOBJECT
  69.  
  70. OBJECT dependancy
  71.   next:PTR TO dependancy
  72.   object:PTR TO object
  73. ENDOBJECT
  74.  
  75. OBJECT action
  76.   next:PTR TO action
  77.   comstring:PTR TO CHAR
  78. ENDOBJECT
  79.  
  80. OBJECT arg
  81.   target,buildfile,force,verbose,nohead,constants
  82. ENDOBJECT
  83.  
  84. OBJECT constant
  85.   next:PTR TO constant
  86.   name:PTR TO CHAR
  87.   subst:PTR TO CHAR
  88. ENDOBJECT
  89.  
  90. DEF curline=0, curstring, uptodate=TRUE, args:PTR TO arg,
  91.     constants:PTR TO constant, -> global list of constants in reverse order
  92.     target:PTR TO CHAR -> holds name of current target
  93.  
  94. PROC main() HANDLE
  95.   DEF m,l,buildfile[200]:STRING,rdargs=NIL
  96.   NEW args
  97.   IF (rdargs:=ReadArgs('TARGET,FROM/K,FORCE/S,VERBOSE/S,NOHEAD/S,CONSTANTS/S',args,NIL))=NIL THEN Raise("barg")
  98.   IF args.buildfile THEN StrCopy(buildfile,args.buildfile)
  99.   StrAdd(buildfile,'.build')
  100.   IF (args.nohead = 0) -> be VERY quiet
  101.     PrintF({versionString})
  102.     PrintF(' (processing "\s")\n', buildfile)
  103.   ENDIF
  104.   m,l:=readfile(buildfile)
  105.   buildtree(parse(stringsinfile(m,l,countstrings(m,l))))
  106.   IF uptodate THEN PrintF('All files are up to date.\n')
  107.   Raise()
  108. EXCEPT
  109.   IF rdargs THEN FreeArgs(rdargs)
  110.   IF exception=0 THEN RETURN
  111.   PrintF('Error: ')
  112.   SELECT exception
  113.     CASE "OPEN"
  114.       PrintF('couldn''t open "\s".\n',exceptioninfo)
  115.     CASE "MEM"
  116.       PrintF('not enough memory.\n')
  117.     CASE "IN"
  118.       PrintF('couldn''t read file.\n')
  119.     CASE "nobj"
  120.       PrintF('action without object.\n')
  121.     CASE "fexp"
  122.       PrintF('filename expected.\n')
  123.     CASE "dexp"
  124.       PrintF('":" or "=" expected.\n')
  125.     CASE "empt"
  126.       PrintF('nothing to build.\n')
  127.     CASE "circ"
  128.       PrintF('circular dependancies at file "\s".\n', exceptioninfo)
  129.     CASE "bada"
  130.       PrintF('action failed to build "\s".\n',exceptioninfo)
  131.     CASE "badd"
  132.       PrintF('dependancy "\s" not available.\n',exceptioninfo)
  133.     CASE "derr"
  134.       PrintF('child process failed.\n')
  135.     CASE "ntar"
  136.       PrintF('no such target: "\s".\n',args.target)
  137.     CASE "ndep"
  138.       PrintF('no dependancies for object "\s".\n',exceptioninfo)
  139.     CASE "clos"
  140.       PrintF('missing closing brace: "\s".\n',exceptioninfo)
  141.     CASE "cons"
  142.       PrintF('unknown constant: "\s".\n',exceptioninfo)
  143.     CASE "barg"
  144.       PrintFault(IoErr(),NIL)
  145.     CASE "scrp"
  146.       PrintF ('unable to create temporary script.\n')
  147.     DEFAULT
  148.       PrintF('burp.\n')
  149.   ENDSELECT
  150.   IF curline THEN PrintF('at line: (\d) "\s"\n',curline,curstring)
  151.   IF exception THEN PrintF('Build terminated\n')
  152.   RETURN 10
  153. ENDPROC
  154.  
  155. PROC parse(list:PTR TO LONG)
  156.   DEF l=NIL:PTR TO object, s, c, i, t, const=NIL:PTR TO constant,str:PTR TO CHAR
  157.   FOR curline:=0 TO ListLen(list)-1
  158.     s:=list[curline]
  159.     curstring:=s
  160.     c:=s[]
  161.     IF (c<>"#") AND (c<>"\0")            -> ignore?
  162.       IF (c=" ") OR (c="\t")            -> action
  163.         s:=eatwhite(s)
  164.         IF s[]
  165.           IF l=NIL THEN Raise("nobj")
  166.           -> was: l.firstaction:=NEW [l.firstaction,s]:action
  167.             -> replaced by the following IF (Rob through Glauschwuffel)
  168.             IF l.lastaction
  169.               l.lastaction.next:=NEW [NIL,s]:action
  170.               l.lastaction:=l.lastaction.next
  171.             ELSE
  172.               l.firstaction:=NEW [NIL,s]:action
  173.               l.lastaction:=l.firstaction
  174.             ENDIF
  175.         ENDIF
  176.       ELSE                    -> object rule or constant
  177.         i:=s
  178.         s:=eatname(s)
  179.         IF s=i THEN Raise("fexp")
  180.         t:=s
  181.  
  182.     IF (s[]<>":") AND (s[]<>"=") THEN Raise("dexp")
  183.         IF s[]=":"
  184.  
  185.       -> check object rule for use of constants
  186.       str:=String(1024) -> dyn. alloc., free if no constants 
  187.       IF str=NIL THEN Raise("MEM")
  188. /*      IF (substituteConstants (i, str)<>0) ->update vars if there were constants
  189.         i := str; s:=eatname(str) -> these were copied from above
  190.             IF s=i THEN Raise("fexp")
  191.             t:=s
  192.       ELSE
  193.         Dispose(str)
  194.       ENDIF
  195. */
  196.       substituteConstants (i, str)
  197.         i := str; s:=eatname(str) 
  198.             IF s=i THEN Raise("fexp")
  199.             t:=s
  200.       
  201.  
  202.           t[]:="\0"
  203.             s++
  204.           s:=eatwhite(s)
  205.           l:=NEW [l,i,NIL,NIL,0]:object
  206.           s:=eatwhite(s)
  207.           IF s[]<>"\0"
  208.             REPEAT
  209.               i:=s
  210.               s:=eatname(s)
  211.               t:=s
  212.               IF t=i THEN Raise("fexp")
  213.               s:=eatwhite(s)
  214.               t[]:="\0"
  215.               l.firstdep:=NEW [l.firstdep,i]:dependancy
  216.             UNTIL s[]="\0"
  217.           ENDIF
  218.           ELSE -> we have a constant
  219.             s++
  220.             s:=eatwhite(s)
  221.           t[]:="\0" -> terminate name
  222.       const:=NEW[const,i,s]:constant
  223.       constants:=const -> have to do it here so consts in rules are recognized
  224.           ENDIF
  225.       ENDIF
  226.     ENDIF
  227.   ENDFOR
  228.   curline:=0
  229.   IF args.constants THEN dumpC()
  230.   IF l=NIL THEN Raise("empt")
  231. ENDPROC l
  232.  
  233.  
  234. PROC eatwhite(s)
  235.   WHILE (s[]=" ") OR (s[]="\t") DO s++
  236. ENDPROC s
  237.  
  238. PROC eatname(s)
  239.   WHILE (s[]<>" ") AND (s[]<>"\t") AND (s[]<>"\0") AND (s[]<>":") AND (s[]<>"=") DO s++
  240. ENDPROC s
  241.  
  242. /* obsolete
  243. PROC execute(c)
  244. DEF s[1024]:STRING
  245.   uptodate:=FALSE
  246.   substituteConstants (c, s)
  247.   IF args.verbose THEN PrintF('\t\s\n', s)
  248. ->  PrintF('\t\s\n',IF substituteConstants (c, s) THEN s ELSE c)
  249.   IF Execute(s,NIL,stdout)=NIL THEN Raise("derr")
  250. ENDPROC */
  251.  
  252. PROC filetime(name:PTR TO CHAR)
  253.   DEF l:PTR TO filelock, fib:fileinfoblock, date:PTR TO datestamp
  254.   IF l:=Lock(name,ACTION_READ)
  255.     IF Examine(l,fib)
  256.       date:=fib.datestamp
  257.       IF fib.direntrytype<0
  258.         UnLock(l)
  259.         RETURN date.days, Shl(date.minute,12)+date.tick
  260.       ENDIF
  261.     ENDIF
  262.     UnLock(l)
  263.   ENDIF
  264. ENDPROC -1
  265.  
  266. PROC timelater(day1,tick1,day2,tick2)
  267.   IF day1>day2
  268.     RETURN TRUE
  269.   ELSEIF day1=day2
  270.     RETURN tick1>tick2
  271.   ENDIF
  272. ENDPROC FALSE
  273.  
  274. /*----------------rob's-stuff-------------------*/
  275.  
  276. PROC buildtree(list:PTR TO object) -> returns root of tree
  277.   DEF dep:PTR TO dependancy,
  278.       obj:PTR TO object
  279.  
  280.   obj:=list
  281.   WHILE obj         -> traverse objects
  282.     dep:=obj.firstdep
  283.     WHILE dep       -> traverse dependencies
  284.       dep.object:=findobject(dep.object,list)
  285.       dep:=dep.next
  286.     ENDWHILE
  287.     obj:=obj.next
  288.   ENDWHILE
  289.  
  290.   -> CHECK CYCLES!!!
  291.  
  292.   obj:=list
  293.   IF args.target
  294.     WHILE obj
  295.       IF StrCmp(args.target,obj.name) THEN JUMP out
  296.       obj:=obj.next
  297.     ENDWHILE
  298.     Raise("ntar")
  299.     out:
  300.   ELSE
  301.     IF obj THEN WHILE obj.next DO obj:=obj.next
  302.   ENDIF
  303.   traverse(obj)
  304. ENDPROC
  305.  
  306.  
  307. -> find object in list of objects by name
  308. PROC findobject(name:PTR TO CHAR,list:PTR TO object)
  309.   WHILE list
  310.     IF StrCmp(name,list.name)
  311.       -> remove object from root list
  312.       list.child:=TRUE;
  313.       RETURN list
  314.     ENDIF
  315.     list:=list.next
  316.   ENDWHILE
  317. ENDPROC NEW [NIL,name,NIL,NIL]:object
  318.  
  319. -> child-first traversal of dependancy tree
  320. PROC traverse(obj:PTR TO object) -> executes actions in tree
  321.   DEF dep:PTR TO dependancy,maxtime1=0,maxtime2=0,time1,time2,action:PTR TO action
  322.  
  323.   IF obj.firstdep OR obj.firstaction    -> object with dependancies/actions
  324.     -> traverse children and get maximum timestamp
  325.     dep:=obj.firstdep
  326.     WHILE dep
  327.       IF OstrCmp (dep.object.name, obj.name) = 0 THEN Throw("circ",obj.name) -> cyclic check by Glauschwuffel
  328.       target := obj.name
  329.       time1,time2:=traverse(dep.object)
  330.       IF timelater(time1,time2,maxtime1,maxtime2)
  331.         maxtime1:=time1
  332.         maxtime2:=time2
  333.       ENDIF
  334.       dep:=dep.next
  335.     ENDWHILE
  336.     time1,time2:=filetime (obj.name)
  337.     IF time1<0 OR timelater(maxtime1,maxtime2,time1,time2) OR args.force
  338.       -> dependancy file(s) more recent: build object
  339.       -> execute actions
  340.       action:=obj.firstaction
  341.  
  342.       buildAndExecuteScript (action)
  343.  
  344.       time1,time2:=filetime(obj.name)
  345.       IF (time1<0) AND (obj.child=TRUE) THEN Throw("bada",obj.name)
  346.     ENDIF
  347.     RETURN time1,time2
  348.   ENDIF
  349.   -> object requires no action: return timestamp
  350.   time1,time2:=filetime(obj.name);
  351.   IF time1<0 THEN Throw("badd",obj.name)
  352. ENDPROC time1,time2
  353.  
  354. /* - glauschwuffel's stuff --- */
  355.  
  356.  
  357. PROC dumpC()
  358. DEF co:PTR TO constant
  359.   co:=constants
  360.   WriteF ('Constants are:\n') 
  361.   WHILE co  
  362.     WriteF('\t<\s> with <\s>.\n', co.name, co.subst)
  363.     co:=co.next
  364.   ENDWHILE
  365. ENDPROC
  366.  
  367. PROC substituteConstants(c:PTR TO CHAR, s:PTR TO CHAR)
  368. -> search c for constants and substitute them
  369. DEF dollar, bclose=-1,sub=NIL
  370.   REPEAT
  371.     bclose++
  372.     dollar := InStr (c,'$(',bclose)
  373.     IF (dollar<>-1) -> found it?
  374.       StrAdd (s, c+bclose, dollar-bclose)
  375.       bclose := InStr (c,')',dollar+2)
  376.       IF bclose=-1 THEN Throw("clos",c)
  377.       sub := findConstant(c,dollar+2,bclose-1)
  378.       IF sub=NIL THEN Throw("cons",c+dollar)
  379.       StrAdd (s,sub)
  380.     ELSE -> copy rest of the line to buffer
  381.       StrAdd (s, c+bclose)
  382.     ENDIF
  383.   UNTIL (dollar=-1) OR (bclose=-1)
  384.   RETURN sub -> did we substitute something at all?
  385. ENDPROC
  386.  
  387. PROC findConstant(c,start,end)
  388. -> find constant of given position in list
  389. -> add 27.07.97: returns global target on target
  390. DEF co:PTR TO constant
  391.   IF OstrCmp('target',c+start,end-start+1)=0 THEN RETURN target
  392.   co:=constants
  393.   WHILE co  
  394.     EXIT (OstrCmp(co.name,c+start,end-start+1)=0)
  395.     co:=co.next
  396.   ENDWHILE
  397.   RETURN IF co THEN co.subst ELSE NIL
  398. ENDPROC
  399.  
  400. PROC buildAndExecuteScript (action:PTR TO action) HANDLE
  401. DEF s[1024]:STRING,
  402.   handle
  403.  
  404.   handle := Open ('T:Ebuild_actions', MODE_NEWFILE) -> open script file
  405.   IF (handle = NIL) THEN Raise ("scrp")
  406.  
  407.   /* create script variable TARGET */
  408.   StrCopy (s, 'Set target ')
  409.   StrAdd (s, target)
  410.   StrAdd (s, '\n') -> add newline
  411.  
  412.   Write (handle, s, StrLen (s))
  413.   IF args.verbose THEN PrintF('\t\s', s)
  414.   
  415.   WHILE action
  416.     uptodate:=FALSE
  417.     SetStr (s, 0) -> "delete" the string of the last action
  418.     substituteConstants (action.comstring, s) -> expand action
  419.     StrAdd (s, '\n') -> add newline
  420.     IF args.verbose THEN PrintF('\t\s', s)
  421.     Write (handle, s, StrLen (s))
  422.     action:=action.next
  423.   ENDWHILE
  424.  
  425.   Close (handle)
  426.   IF Execute('Execute T:Ebuild_actions', NIL, stdout)=NIL THEN Raise("derr")
  427.   DeleteFile ('T:EBuild_actions')
  428.  
  429. EXCEPT
  430.   IF handle THEN Close(handle)
  431.   ReThrow()
  432. ENDPROC
  433.  
  434.  
  435. versionTag: CHAR 0,'$VER:'
  436. versionString: CHAR 'EBuild 0.92 (12.10.97) ©1997 Rob, Wouter and Glauschwuffel',0
  437.  
  438.